//
// Created by 34649 on 2022/3/1.
//
#include "include/http_decoder.h"
using namespace http;

http_decoder::http_decoder(const http::string &src) : src(src),_pos(0) {
    if((parse_code=parse_http()) != HTTP_PARSE_CODE::OK){
        LOG_ERROR<<static_cast<int>(parse_code);
    };
}
http_decoder::http_decoder(Buffer *buffer) :_buffer(buffer),status(HTTP_PARSE_STATUS::INIT){
    init();
}

http::string http::http_decoder::getLine() {
    bool flag;
    return getLine(flag);
}
string http_decoder::getLine(bool& flag) {
    const char * end= _buffer->findCRLF();
    flag=true;
    if(end){
        string res=_buffer->retrieveAsString(end-_buffer->peek());
        LOG_INFO<<res;
        _buffer->retrieveUntil(end+2);
        return res;
    }else{
        flag=false;
        LOG_WARN<<"get empty line!";
    }
    return string();
}

HTTP_PARSE_CODE http::http_decoder::parse_http() {
//    HTTP_PARSE_CODE parse_code;
    if(status==HTTP_PARSE_STATUS::REQUEST_LINE){
        LOG_INFO<<"parse request line!";
        if((parse_code=read_questLine()) == HTTP_PARSE_CODE::OK){//判断解析是否成功
            status=HTTP_PARSE_STATUS::HEADER;
        }else{
            LOG_ERROR<<"read_questLine:"<< std::to_string(static_cast<int>(parse_code));
            return parse_code;
        }
    }
    if(status==HTTP_PARSE_STATUS::HEADER){
        LOG_INFO<<"parse header!";
        if((parse_code=read_header()) != HTTP_PARSE_CODE::OK){
            if(parse_code == HTTP_PARSE_CODE::NO_CONTENT){//没有content直接返回
                parse_code=HTTP_PARSE_CODE::OK;
                return parse_code;
            }
            LOG_ERROR<<"read_header:"<< std::to_string(static_cast<int>(parse_code));
            return parse_code;
        }
    }
    if(status==HTTP_PARSE_STATUS::CONTENT){
        LOG_INFO<<"parse content!";
        parse_code=read_content();
        if(parse_code == HTTP_PARSE_CODE::INCOMPLATE_PACK || parse_code == HTTP_PARSE_CODE::OK){
            parse_code=HTTP_PARSE_CODE::OK;
            return parse_code;
        }
    }
    return parse_code;
}

HTTP_PARSE_CODE http::http_decoder::read_questLine() {//需要适配一些错误情况
    string temp = getLine(), temp_method, temp_version;
    int i = 0;
    for(; i<temp.size(),temp[i] != ' '; i++)temp_method += temp[i];
    if(temp_method == "GET"){
        this->_method = METHOD::GET;
    }
    else if(temp_method == "POST"){
        this->_method = METHOD::POST;
    }
    else if(temp_method == "PUT"){
        this->_method = METHOD::PUT;
    }
    else if(temp_method == "DELETE"){
        this->_method = METHOD::DELETE;
    }
    else {
        return HTTP_PARSE_CODE::UNKNOWN_HTTP_METHOD;
    }
    for(++i; i<temp.size(),temp[i] != ' '; i++)this->_url += temp[i];
    for(++i; i < temp.length(); i++)temp_version += temp[i];
    if(temp_version == "HTTP/1.0"){
        this->_httpVersion = HTTP_VERSION::HTTP_1;
    }
    else if(temp_version == "HTTP/1.1"){
        this->_httpVersion = HTTP_VERSION::HTTP_11;
    }
    else if(temp_version == "HTTP/2.0"){
        this->_httpVersion = HTTP_VERSION::HTTP_2;
    }
    else if(temp_version == "HTTP/3.0"){
        this->_httpVersion = HTTP_VERSION::HTTP_3;
    }
    else {
        return HTTP_PARSE_CODE::UNKNOWN_HTTP_VERSION;
    }
    return HTTP_PARSE_CODE::OK;
}

HTTP_PARSE_CODE http::http_decoder::read_header() {
    string str;
    bool flag=true;
    while((str=getLine(flag)).size()!=0){
        string key= split_line(str,':');
        string value= str;
        toLowerStr(key);
        toLowerStr(value);
        if(_map.find(key)==_map.end()){
            _map[key]=value;
        }else{
            LOG_ERROR<<"duplicate key error!";
            LOG_ERROR<<"duplicate key:"<<key<<"\nvalue:"<<value;
            return HTTP_PARSE_CODE::DUPLICATE_KEY_ERROR;
        }
    }
    if(flag){
        if(_httpVersion==HTTP_VERSION::HTTP_1&&(_map.find("connection")==_map.end()||_map["connection"]=="close")){//判断是否需要保持长连接
            keep_alived= false;
        }else{
            keep_alived=true;
        }
        if(_map.find("content-type")!=_map.end()){
            string value=_map["content-type"];
            if(value.find("multipart/form-data")==0){
                _content_type=CONTENT_TYPE::FORM_DATA;
                int pos=value.find("boundary");
                _boundary="--";
                _boundary+=value.substr(pos+1);
            }else if(value.find("application/xml")==0){
                _content_type=CONTENT_TYPE::XML;
            }else if(value.find("application/javascript")==0){
                _content_type=CONTENT_TYPE::JAVASCRIPT;
            }else if(value.find("text/plain")==0){
                _content_type=CONTENT_TYPE::PLAIN;
            }else if(value.find("text/html")==0){
                _content_type=CONTENT_TYPE::HTML;
            }else if(value.find("application/json")==0){
                _content_type=CONTENT_TYPE::JSON;
            }else if(value.find("application/x-www-form-urlencoded")){
                _content_type=CONTENT_TYPE::FORM_URLENCODED;
            }else{
                LOG_ERROR<<"content-type parse error! content-type:"<<value;
                return HTTP_PARSE_CODE::UNDEFINED_VALUE;
            }
        }else{
            _content_type=CONTENT_TYPE::NONE;
        }
        if(_map.find("content-length")!=_map.end()){
            string value=_map["content-length"];
            _content_length= std::stoi(value);
            LOG_INFO<<"_content_length:"<< value;
        }else{
            status=HTTP_PARSE_STATUS::FINISHED;
            return HTTP_PARSE_CODE::NO_CONTENT;
        }
        status=HTTP_PARSE_STATUS::CONTENT;
    }
    return HTTP_PARSE_CODE::OK;
}

HTTP_PARSE_CODE http::http_decoder::read_content() {
    if(_content_length<=_buffer->readableBytes()) {
        _content += _buffer->retrieveAsString(_content_length);
        status = HTTP_PARSE_STATUS::FINISHED;
        return HTTP_PARSE_CODE::OK;
    }
    _content_length-=_buffer->readableBytes();
    _content+=_buffer->retrieveAllAsString();
    _buffer->retrieveAll();
    LOG_WARN<<"incomplete package!";
    return HTTP_PARSE_CODE::INCOMPLATE_PACK;
}

http::string http::http_decoder::split_line(http::string &str) {
    assert(str.size()!=0);
    int pos=str.find(" ");
    string res=str.substr(0,pos);
    while(pos<str.size()&&str[pos]==' '){
        pos++;
    }
    str=str.substr(pos);
    return res;
}

string http_decoder::split_line(string &str, char de) {
    assert(str.size()!=0);
    int pos=str.find(de);
    string res=str.substr(0,pos);
    pos++;//跳过当前的分隔符
    while(pos<str.size()&&str[pos]==' '){//去除多余的空格
        pos++;
    }
    str=str.substr(pos);
    return res;
}

void http_decoder::init() {
    status=HTTP_PARSE_STATUS::REQUEST_LINE;
    _map.empty();
    _content_length=0;
    _content="";
    LOG_WARN<<"decoder init!";
}

http_decoder::~http_decoder() {
    LOG_WARN<<"decoder destory!";
}


